// Decompiled by DJ v3.9.9.91 Copyright 2005 Atanas Neshkov  Date: 1/7/2014 5:57:03 PM
// Home Page : http://members.fortunecity.com/neshkov/dj.html  - Check often for new version!
// Decompiler options: packimports(3) 
// Source File Name:   KittyCache.java

package com.spaceprogram.kittycache;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;

// Referenced classes of package com.spaceprogram.kittycache:
//            KCache

public class KittyCache
    implements KCache
{
    public class CacheEntry
    {

        public long getExpireBy()
        {
            return expireBy;
        }

        public Object getEntry()
        {
            return entry;
        }

        private long expireBy;
        private Object entry;

        public CacheEntry(long expireBy, Object entry)
        {
            this.expireBy = expireBy;
            this.entry = entry;
        }
    }


    public KittyCache(int maxSize)
    {
        cacheSize = new AtomicInteger();
        this.maxSize = maxSize;
        cache = new ConcurrentHashMap<Object, CacheEntry>(maxSize);
        queue = new ConcurrentLinkedQueue<Object>();
    }

    public Object get(Object key)
    {
        if(key == null)
            throw new IllegalArgumentException("Invalid Key.");
        CacheEntry entry = (CacheEntry)cache.get(key);
        if(entry == null)
            return null;
        long timestamp = entry.getExpireBy();
        if(timestamp != -1L && System.currentTimeMillis() > timestamp)
        {
            remove(key);
            return null;
        } else
        {
            return entry.getEntry();
        }
    }

    public Object removeAndGet(Object key)
    {
        if(key == null)
            return null;
        CacheEntry entry = (CacheEntry)cache.get(key);
        if(entry != null)
        {
            cacheSize.decrementAndGet();
            return ((CacheEntry)cache.remove(key)).getEntry();
        } else
        {
            return null;
        }
    }

	public void put(Object key, Object value, int secondsToLive)
    {
        if(key == null)
            throw new IllegalArgumentException("Invalid Key.");
        if(value == null)
            throw new IllegalArgumentException("Invalid Value.");
        long expireBy = secondsToLive == -1 ? secondsToLive : System.currentTimeMillis() + (long)(secondsToLive * 1000);
        boolean exists = cache.containsKey(key);
        if(!exists)
        {
            cacheSize.incrementAndGet();
            for(; cacheSize.get() > maxSize; remove(queue.poll()));
        }
        cache.put(key, new CacheEntry(expireBy, value));
        queue.add(key);
    }

    public boolean remove(Object key)
    {
        return removeAndGet(key) != null;
    }

    public int size()
    {
        return cacheSize.get();
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
	public Map getAll(Collection collection)
    {
        Map ret = new HashMap();
        Object o;
        for(Iterator iterator = collection.iterator(); iterator.hasNext(); ret.put(o, get(o)))
            o = (Object)iterator.next();

        return ret;
    }

    public void clear()
    {
        cache.clear();
    }

    public int mapSize()
    {
        return cache.size();
    }

    public int queueSize()
    {
        return queue.size();
    }
    
    public Set<Object> GetCacheKey()
    {
    	return cache.keySet();
    }

    private Map<Object, CacheEntry> cache;
    private Queue<Object> queue;
    private int maxSize;
    private AtomicInteger cacheSize;
	
}